package com.sfx.messagequeue.mqServer.core;

import com.sfx.messagequeue.common.exception.MQException;

import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 * Description: 这个类主要实现路由规则
 * User: sfx
 * Date: 2023-08-06
 * Time: 16:31
 */
public class Router {

    public boolean checkBindingKey(String bindingKey) {
        //0. bindingKey==null的情况,如果是Fanout/Direct交换机,那么就是合法的,-->Direct直接使用队列名字 or FANOUT
        if (bindingKey == null) {
            return true;
        }
        //1. 是否符合routingKey的规则,包含,数字,字母,下划线
        for (char c : bindingKey.toLowerCase().toCharArray()) {
            //1.1 数字
            if (c >= '0' && c <= '9') {
                continue;
            }
            //1.2 字母
            if (c >= 'a' && c <= 'z') {
                continue;
            }
            //1.3 特殊符号  .   *  #
            if (c == '_' || c == '.' || c == '*' || c == '#') {
                continue;
            }
            return false;
        }

        //2. 处理特殊的匹配规则,按照 . 进行分割所有字符
        String[] split = bindingKey.split("\\.");
        // . or # 必须是 独立的
        for (String s : split) {
            if (s.length() > 1 && (s.contains("*") || s.contains("#"))) {
                return false;
            }
        }
        //  * : 可以匹配任何一个独立的部分
        //  # : 可以匹配任何0个或者多个独立的部分.
        // a.#.#.b => 非法
        // a.*.#.b => 非法
        // a.#.*.b => 非法
        // a.*.*.b => 合法
        for (int i = 0; i < split.length - 1; i++) {
            if (split[i].equals("#") && split[i + 1].equals("#")) {
                return false;
            }
            if (split[i].equals("#") && split[i + 1].equals("*")) {
                return false;
            }
            if (split[i].equals("*") && split[i + 1].equals("#")) {
                return false;
            }
        }
        return true;
    }

    public boolean checkRoutingKey(String routingKey) {
        //0. routingKey==null的情况,如果是FANOUT交换机,那么就是合法的
        if (routingKey == null) {
            return true;
        }
        //1. 是否符合routingKey的规则,包含,数字,字母,下划线
        for (char c : routingKey.toLowerCase().toCharArray()) {
            //1.1 数字
            if (c >= '0' && c <= '9') {
                continue;
            }
            //1.2 字母
            if (c >= 'a' && c <= 'z') {
                continue;
            }
            //1.3 特殊符号  .   *  #
            if (c == '_' || c == '.' || c == '*' || c == '#') {
                continue;
            }
            return false;
        }
        return true;
    }

    public boolean route(ExchangeType type, Binding binding, Message message) throws MQException {
        if (type == ExchangeType.FANOUT) {
            //FANOUT扇出交换机,直接返回true.它是需要给交换机关联的所有队列都发送消息
            return true;
        } else if (type == ExchangeType.TOPIC) {
            //如果是 TOPIC 类型的交换机,必须routingKey和BindingKey对上暗号才可以
            return routeTopic(binding,message);
//            return routeTopic(binding, message);
        } else {
            throw new MQException("[Router] 交换机类型不存在 exchangeType=" + type);
        }
    }

    /**
     * topic路由转发规则编写代码
     *
     * @param binding 绑定
     * @param message 消息
     * @return 返回是否能够转发
     */
    private boolean routeTopic(Binding binding, Message message) {
        // 1. 将其binding,message进行拆分得到 bindingKey,routingKey
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");
        // 2. 定义两指针进行比较
        int bindingIndex = 0;
        int routingIndex = 0;
        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length) {
            // 3. 如果遇到 * , 两指针都 ++
            if (bindingTokens[bindingIndex].equals("*")) {
                bindingIndex++;
                routingIndex++;
            } else if (bindingTokens[bindingIndex].equals("#")) {
                // 4. 如果遇到 # , 要去查看#后面有没有字符串了
                ++bindingIndex;
                if (bindingIndex == bindingTokens.length) {
                    //到达bindingTokens结尾,后面没有字符串了
                    return true;
                }
                // 5. 如果后面还有,那么拿着后面的字符串 在routingKey 寻找,看有没有
                routingIndex = getNextRoutingStr(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                // 6. 如果没有,返回
                if (routingIndex == -1) {
                    return false;
                }
                // 7. 找到之后两指针往后移动
                bindingIndex++;
                routingIndex++;
            } else {
                // 8. 判断普通字符串是否相等,相等则++,不相等则返回
                if (!routingTokens[routingIndex].equals(bindingTokens[bindingIndex])) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        return routingIndex == routingTokens.length && bindingIndex == bindingTokens.length;
    }

    private int getNextRoutingStr(String[] routingTokens, int routingIndex, String target) {
        for (int i = routingIndex; i < routingTokens.length; i++) {
            if (routingTokens[i].equals(target)) {
                return i;
            }
        }
        return -1;
    }

//    public boolean isMatch(Binding binding, Message message) {
//        String[] s = binding.getBindingKey().split("\\.");
//        s = Arrays.copyOf(s, s.length + 1);
//        for(int i =s.length-1;i>0;--i) {
//            s[i] = s[i-1];
//        }
//        s[0] = " ";
//
//        String[] p = message.getRoutingKey().split("\\.");
//        p = Arrays.copyOf(p, p.length + 1);
//        for(int i =p.length-1;i>0;--i) {
//            p[i] = p[i-1];
//        }
//        p[0] = " ";
//
//        //1.dp[i][j]=true[0...j]的p字符串能够匹配[0...i]的s字符串
//        int m = s.length;
//        int n = p.length;
//        boolean[][] dp = new boolean[m+1][n+1];
//        //2.状态转移方程
//        //p[i]是不同字符,s[i]==p[j]&&dp[i-1][j-1] dp[i][j]=true
//        //p[i]是 '?' dp[i-1][j-1] ->dp[i][j]=true
//        //p[i]是 '*' dp[i-1][j-1] || dp[i-2][j-1] || dp[i-3][j-1] || .....
//        // 因为  dp[i][j] = dp[i][j-1] || dp[i-1][j-1] || dp[i-2][j-1]
//        //      dp[i-1][j] =                  dp[i-1][j-1] || dp[i-2][j-1] || dp[i-3][j-1]
//        //dp[i-1][j] = dp[i][j-1] || dp[i-1][j]
//        //3.初始化
//        // 多加一行,多加一列
//        //dp[0][0]= true
//        //dp[i][0]= false
//        //dp[0][j]= *
//        dp[0][0] = true;
//        for(int j =1;j<=n;++j) {
//            if(p[j].equals("#")) dp[0][j]=true;
//            else  break;
//        }
//        //4.填表顺序
//        //从左往右,从上往下
//        for(int i =1;i<=m;++i) {
//            for(int j =1;j<=n;++j) {
//                if(p[j].equals("#")) {
//                    dp[i][j] = dp[i][j-1] || dp[i-1][j];
//                }else{
//                    dp[i][j] = (p[j].equals("*")|| p[j].equals(s[i])) && dp[i - 1][j - 1];
//                }
//            }
//        }
//        //5.返回值
//        return dp[m][n];
//    }
}